#!/usr/bin/env python
# -*- coding: UTF-8 -*-
"""
@Project ：python_learning 
@File ：访问者模式.py
@IDE  ：PyCharm 
@Author ：李涵彬
@Date ：2024/3/1 23:23 
"""

"""
访问者模式 (Visitor Pattern)
访问者模式是一种行为型设计模式，它用于在不改变对象结构的情况下，为对象结构中的每个元素提供新的操作。这种模式的关键是能够将操作从表示对象的类中分离出来。

在 Python 中，访问者模式通常通过定义一个访问者接口以及具体的访问者类来实现。以下是一个简单的示例：

在这个示例中，Visitor 是访问者接口，定义了对元素进行访问的方法。ConcreteVisitorA 和 ConcreteVisitorB 是具体的访问者类，实现了访问不同元素的具体操作。

Element 是元素接口，定义了接受访问者的方法。ConcreteElementA 和 ConcreteElementB 是具体的元素类，实现了接受访问者的方法。

ObjectStructure 是结构对象，维护了一个元素列表，并提供了接受访问者的方法。

客户端代码创建具体的访问者对象、元素对象和结构对象，并将元素对象添加到结构对象中，然后通过调用结构对象的接受方法来接受访问者。

访问者模式适用于需要为对象结构中的每个元素提供不同操作的情况。通过使用访问者模式，可以将操作从元素的类中分离出来，使得每个元素的类更加简单和独立。
"""

from abc import ABC, abstractmethod


# 访问者接口
class Visitor(ABC):
	@abstractmethod
	def visit_element_a(self, element):
		pass

	@abstractmethod
	def visit_element_b(self, element):
		pass


# 具体访问者A
class ConcreteVisitorA(Visitor):
	def visit_element_a(self, element):
		print("具体访问者A访问元素A")

	def visit_element_b(self, element):
		print("具体访问者A访问元素B")


# 具体访问者B
class ConcreteVisitorB(Visitor):
	def visit_element_a(self, element):
		print("具体访问者B访问元素A")

	def visit_element_b(self, element):
		print("具体访问者B访问元素B")


# 元素接口
class Element(ABC):
	@abstractmethod
	def accept(self, visitor):
		pass


# 具体元素A
class ConcreteElementA(Element):
	def accept(self, visitor):
		visitor.visit_element_a(self)


# 具体元素B
class ConcreteElementB(Element):
	def accept(self, visitor):
		visitor.visit_element_b(self)


# 结构对象
class ObjectStructure:
	def __init__(self):
		self._elements = []

	def attach(self, element):
		self._elements.append(element)

	def detach(self, element):
		self._elements.remove(element)

	def accept(self, visitor):
		for element in self._elements:
			element.accept(visitor)


# 客户端代码
if __name__ == "__main__":
	visitor_a = ConcreteVisitorA()
	visitor_b = ConcreteVisitorB()

	element_a = ConcreteElementA()
	element_b = ConcreteElementB()

	object_structure = ObjectStructure()
	object_structure.attach(element_a)
	object_structure.attach(element_b)

	object_structure.accept(visitor_a)
	object_structure.accept(visitor_b)
